package com.token.sql;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Vector;
/**
 * Bean基础类
 * @author chenjianxiong 2020/3/26
 */
public abstract class AbstractTableBean {
    protected PrepareSql prepareSql;
    protected IntegrateSql integrateSql;
    protected String tableName;
    private String keyId;
    private String keyName;
    private boolean isUpdate = false;
    private boolean isInitRs = false;
    public IntegrateSql getIntegrateSql() {
        return integrateSql;
    }


    public boolean isInitRs() {
            return isInitRs;
    }
    /**
     * 获取主键名
     * @return String
     */
    public String getKeyName() {
        return keyName;
    }

    /**
     * 设置主键名
     * @param keyName 主键名
     */
    public void setKeyName(String keyName) {
        this.keyName = keyName;
    }

    /**
     * 获取表名
     * @return String
     */
    public String getTableName() {
        return tableName;
    }

    /**
     * 获取主键值
     * @return String
     */
    public String getKeyId() {
        return keyId;
    }

    /**
     * 设置主键值
     * @param keyId n
     */
    public void setKeyId(String keyId) {
        this.keyId = keyId;
        isInitRs = true; //这一句必需要加。
    }

    /**
     * 是否更新
     * @return boolean true是update false是insert
     */
    public boolean isUpdate() {
        return isUpdate;
    }

    /**
     * sql 代码。
     * @return sql
     */
    public StringBuffer selectCode(){
        StringBuffer sql = new StringBuffer(50);
        sql.append("SELECT * FROM ").append(this.tableName).append(" ");
        return sql;
    }

    /**
     * select * from table where keyname=?
     * @return sql
     */
    public StringBuffer selectCodeById(){
        StringBuffer sql = new StringBuffer(50);
        sql.append("SELECT * FROM ")
                .append(this.tableName)
                .append(" where ")
                .append(this.keyName)
                .append("=?");
        return sql;
    }
    /**
     * 构造函数
     * @param f 类库
     * @param tableName 表名
     */
    public AbstractTableBean(IntegrateSql f,String tableName){
        this.integrateSql = f;
        this.tableName = tableName;
        this.keyId = "";
        this.prepareSql = new PrepareSql(integrateSql);
    }


    /**
     * 构造函数
     * @param f 类库
     * @param tableName 表名
     * @param keyId 主键值
     */
    public AbstractTableBean(IntegrateSql f,String tableName,String keyId){
        this.integrateSql = f;
        this.keyId = keyId;
        this.tableName = tableName;
        this.prepareSql = new PrepareSql(integrateSql);
    }

    /**
     * 插入或更新数据，根据主键值判断。
     * @param keyName 主键字段名
     * @param keyValue 主键值
     * @throws SQLException 抛出错误
     */
    public void setInsertOrUpdate(String keyName,String keyValue) throws SQLException{
        if(integrateSql.selectCount(this.tableName,keyName,keyValue) == 1){
            this.setUpdate(keyName, keyValue);
        }else{
            this.setInsert();
        }
    }
    /**
     * 插入或更新
     * @param keyValue 主键值
     * @throws SQLException 抛出错误
     */
    public void setInsertOrUpdate(String keyValue) throws SQLException{
        if(integrateSql.selectCount(this.tableName,this.keyName,keyValue) == 1){
            this.setUpdate(keyName, keyValue);
        }else{
            this.setInsert();
        }
    }

    /**
     * 插入或更新当前keyValue主键的记录。
     * @param keyValue 主键值
     * @throws SQLException 抛出错误
     */
    public void setInsertOrUpdateRs(String keyValue) throws SQLException{
        this.prepareSql.setPrepare(this.selectCodeById());
        this.prepareSql.setPstValue(1,keyValue);
        ResultSet rs = prepareSql.executeQuery();
        if(rs.next()){
            this.initParamToRs(rs);
            rs.close();
            this.setUpdateCur();
        }else{
            rs.close();
            this.setInsert();
        }

    }
    /**
     * 插入数据
     * @throws SQLException 抛出错误
     */
    public void setInsert() throws SQLException{
        Vector<String> fields = this.getFields();
        String sql = this.prepareSql.insertDataStr(tableName, fields);
        this.prepareSql.setPrepare(sql);
        this.isUpdate = false;
        this.initParam();
    }

    /**
     *在写入前根据主键先读取记录回写。
     * @param keyValue 主键Id
     * @throws Exception
     */
    public void setInsert(Object keyValue) throws Exception{
        if(keyValue == null || !this.initParamToRs(keyValue)){
            throw new Exception("不存在记录：【"+ keyValue +"】");
        }
        Vector<String> fields = this.getFields();
        String sql = this.prepareSql.insertDataStr(tableName, fields);
        this.prepareSql.setPrepare(sql);
        this.isUpdate = false;

    }
    /**
     *
     * 插入数据，并可读取主键ID
     * @throws SQLException 抛出错误
     */
    public void setInsertReturnId() throws SQLException{
        Vector<String> fields = this.getFields();
        String sql = this.prepareSql.insertDataStr(tableName, fields);
        this.prepareSql.setPrepareReturnKey(sql);
        this.isUpdate = false;
        this.initParam();
    }

    /**
     * 在写入前根据主键先读取记录回写,返回Id
     * @param keyValue 主键Id
     * @throws Exception
     */
    public void setInsertReturnId(Object keyValue) throws Exception{
        if(keyValue == null || !this.initParamToRs(keyValue)){
            throw new Exception("不存在记录：【"+ keyValue +"】");
        }
        Vector<String> fields = this.getFields();
        String sql = this.prepareSql.insertDataStr(tableName, fields);
        this.prepareSql.setPrepareReturnKey(sql);
        this.isUpdate = false;
    }

    /**
     * 更新数据
     * @param keyName 主键字段名
     * @param keyValue 主键值
     * @throws SQLException 抛出错误
     */
    public void setUpdate(String keyName,String keyValue) throws SQLException{
        Vector<String> fields = this.getFields();
        String sql = this.prepareSql.updateDataStr(tableName,fields,keyName);
        this.prepareSql.setPrepare(sql);
        this.isUpdate = true;
        this.setKeyId(keyValue);
        this.initParam();
    }

    /**
     * 不对参数初始化
     * @param keyName 主键字段名
     * @throws SQLException 抛出错误
     */
    public void setUpdateCur(String keyName) throws SQLException{
        Vector<String> fields = this.getFields();
        String sql = this.prepareSql.updateDataStr(tableName,fields,keyName);
        this.prepareSql.setPrepare(sql);
        this.isUpdate = true;
    }

    /**
     * 更新当前
     * @throws SQLException 抛出错误
     */
    public void setUpdateCur() throws SQLException{
        this.setUpdateCur(this.keyName);

    }

    /**
     * 检索由于执行此 Statement 对象而创建的所有自动生成的键
     * @return key
     * @throws SQLException 抛出错误
     */
    public String getGeneratedStringKeys() throws SQLException{
        return this.prepareSql.getGeneratedStringKeys();
    }

    /**
     * 检索由于执行此 Statement 对象而创建的所有自动生成的键
     * @return long
     * @throws SQLException 抛出错误
     */
    public long getGeneratedLongKeys() throws SQLException{
        return this.prepareSql.getGeneratedLongKeys();
    }

    /**
     * 批量执行。
     * @throws SQLException 抛出错误
     */
    public void executeBatch() throws SQLException{
        this.prepareSql.executeBatch();
    }

    /**
     * 执行executeUpdate
     * @throws SQLException 抛出错误
     */
    public void executeUpdate() throws SQLException{
        if(this.isUpdate){
            this.appendData(this.keyId);
        }else{
            this.appendData();
        }
        this.prepareSql.executeUpdate();
    }

    /**
     * 添加批处理
     * @throws SQLException 抛出错误
     */
    public void addBatch() throws SQLException{
        if(this.isUpdate){
            this.appendData(this.keyId);
        }else{
            this.appendData();
        }
        this.prepareSql.addBatch();
    }

    /**
     * 关闭
     * @throws SQLException 抛出错误
     */
    public void close() throws SQLException{
        if(this.prepareSql != null) {
            prepareSql.close();
        }
    }

    /**
     * 预编sql
     * @param sql sql
     * @throws SQLException 抛出错误
     */
    public void setCodePrepare(String sql) throws SQLException{
        prepareSql.setPrepare(sql);
    }

    /**
     * 执行SQL
     * @return 结果集
     * @throws SQLException 抛出错误
     */
    public ResultSet executeQuery() throws SQLException{
        return prepareSql.executeQuery();
    }

    /**
     * 字段数组
     * @return Vector
     */
    public abstract Vector<String> getFields();

    /**
     * 初始化参数
     */
    protected abstract void initParam();

    /**
     * 初始化参数
     * @param rs 结果集
     * @throws SQLException 抛出错误
     */
    public abstract void initParamToRs(ResultSet rs) throws SQLException;

    /**
     * 初始化参数
     * @param keyValue 主键值
     * @return true 记录存在 false 记录不存在
     * @throws SQLException 抛出错误
     */
    public boolean initParamToRs(Object keyValue) throws SQLException{
        this.prepareSql.setPrepare(this.selectCodeById());
        this.prepareSql.setPstValue(1,keyValue);
        ResultSet rs = this.prepareSql.executeQuery();
        boolean b = initRs(rs);
        rs.close();
        return b;
    }

    /**
     *
     * @param rs
     * @return
     * @throws SQLException
     */
    private boolean initRs(ResultSet rs) throws SQLException{
        if(rs.next()) {
            this.initParamToRs(rs);
            isInitRs = true;
        }else{
            this.initParam();
            isInitRs = false;

        }
        return isInitRs;
    }
    /**
     *
     * @param strWhere where 条件，不需要写where 语句。
     * @param keyValue 值，对应where上的？
     * @return true 初始化成功
     * @throws SQLException 抛出错误
     */
    public boolean initParamToRs(String strWhere,Vector<String> keyValue) throws SQLException{
        prepareSql.setPrepare(this.selectCode().append(" where ").append(strWhere));
        int i=1;
        for(String vec: keyValue){
            prepareSql.setPstValue(i++,vec);
        }

        ResultSet rs = prepareSql.executeQuery();
        boolean b = initRs(rs);
        rs.close();
        return b;
    }


    /**
     *
     * @param keyName 字段名
     * @param keyValue 字段值
     * @return true 初始化成功
     * @throws SQLException 抛出错误
     */
    public boolean initParamToRs(String keyName,String keyValue) throws SQLException{
        prepareSql.setPrepare(this.selectCode().append(" where ").append(keyName).append("=?"));
        prepareSql.setPstValue(1,keyValue);
        ResultSet rs = prepareSql.executeQuery();
        boolean b = initRs(rs);
        rs.close();
        return b;
    }


    /**
     * 添加数据
     * @return int
     * @throws SQLException 抛出错误
     */
    protected abstract int appendData() throws SQLException;

    /**
     * update 使用
     * @param keyValue 主键值
     * @throws SQLException 抛出错误
     */
    protected void appendData(String keyValue) throws SQLException {
        int i = this.appendData();
        if(keyValue != null && !"".equals(keyValue)){
            prepareSql.setPstValue(i,keyValue);
        }
    }
}
